/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-06-25     hehung       the first version
 */

/*
 * 重要说明：如果想要成功显示天气信息，必须将该文件以及app_codetab.h文件修改为utf-8格式的，因为获取的
 * 天气信息中文字符就是utf-8格式，而且代码中也是这么处理的，不然不能显示
 *
 * */

#include "app_display.h"
#include "ssd1306.h"
#include "oled_codetab.h"
#include <rtthread.h>
#include <rtdevice.h>
#include <arpa/inet.h>
#include <netdev.h>
#include "app_pluse_sensor.h"
#include "app_rtc.h"
#include "app_weather.h"
#include "app_bigiot.h"
#include "app_esp8266.h"
#include "app_hw_i2c.h"


#define THREAD_STACK_SIZE_DISP                (5120u)
#define THREAD_PRIORITY_DISP                  (9U)


static rt_thread_t thread_disp_hd = RT_NULL;
static e_DispFlag disp_flg = DISP_INIT;
static e_DispFlag disp_flg_last = DISP_INIT;
static uint32_t thread_cycle = 20;    /* ms */

static e_SettingType setting_flag = SETTING_UPDATE_NTP;
static rt_bool_t ntp_update_flag = RT_FALSE;
static rt_bool_t weather_update_flag = RT_FALSE;

static void Disp_Init(void);
static void Disp_Thread_Entry(void *para);
static void OLED_ShowHz(uint8_t x, uint8_t y, const char hz_c[], SSD1306_COLOR color);
static void OLED_ShowHzStringRow(uint8_t x, uint8_t y, const char *hz_s, SSD1306_COLOR color);
static void Disp_ShowElectrocardiogram(void);
static void Disp_ShowTime(void);
static void Disp_ShowWeatherUpdate(void);
static int myabs(int a);
static void OLED_DrawBmpImg(uint8_t x,
                     uint8_t y,
                     const uint8_t bmp[][8],
                     uint32_t len,
                     uint8_t size,
                     SSD1306_COLOR color);
static void Disp_ShowSetting(void);


void Disp_TaskCreate(void)
{
    thread_disp_hd = rt_thread_create("disp_oled",
                                    Disp_Thread_Entry,
                                    RT_NULL,
                                    THREAD_STACK_SIZE_DISP,
                                    THREAD_PRIORITY_DISP,
                                    10);
    if (RT_NULL != thread_disp_hd)
    {
        rt_thread_startup(thread_disp_hd);
    }
}

/* Display任务入口 */
static void Disp_Thread_Entry(void *para)
{
    while(1)
    {
        switch (disp_flg)
        {
            case DISP_INIT:
            {
                Disp_Init();
                disp_flg = DISP_TIME;
                rt_thread_mdelay(2000);
                break;
            }
            case DISP_TIME:
            {
                Disp_ShowTime();
                break;
            }
            case DISP_WAVEFORM:
            {
                Disp_ShowElectrocardiogram();
                break;
            }
            case DISP_SETTING:
            {
                Disp_ShowSetting();
                break;
            }
            case DISP_UPDATE_WEATHER:
            {
                Disp_ShowWeatherUpdate();
                break;
            }
        }
        rt_thread_mdelay(thread_cycle);
    }
}

static void Disp_Init(void)
{
    i2c_config();

    ssd1306_Init();

    ssd1306_Fill(Black);
    ssd1306_SetCursor(4, 0);
    ssd1306_WriteString("Nation", Font_7x10, White);
    ssd1306_SetCursor(68, 0);
    ssd1306_WriteString("elecfans", Font_7x10, White);
    OLED_ShowHzStringRow(20, 24, (const char *)"心率监控仪", 1);
    ssd1306_SetCursor(74, 50);
    ssd1306_WriteString("-hehung", Font_7x10, White);
    ssd1306_UpdateScreen();
}

static void Disp_ShowSetting(void)
{
    // 清空屏幕buffer
    ssd1306_Fill(Black);

    OLED_DrawBmpImg(18, 20, time_logo_24bit, LOGO_SIZE(time_logo_24bit), 24, !(setting_flag == SETTING_UPDATE_NTP));
    OLED_DrawBmpImg(52, 20, sun_logo_24bit, LOGO_SIZE(sun_logo_24bit), 24, !(setting_flag == SETTING_UPDATE_WEATHER));
    OLED_DrawBmpImg(90, 20, exit_logo_24bit, LOGO_SIZE(exit_logo_24bit), 24, !(setting_flag == SETTING_EXIT));

    if (SETTING_UPDATE_NTP == setting_flag)
    {
        OLED_ShowHzStringRow(32, 48, (const char *)"更新时间", 1);
        if (RT_TRUE == ntp_update_flag)
        {
            OLED_ShowHzStringRow(16, 0, (const char *)"正在更新时间", 1);
        }
    }
    else if (SETTING_UPDATE_WEATHER == setting_flag)
    {
        OLED_ShowHzStringRow(32, 48, (const char *)"更新天气", 1);
        if (RT_TRUE == weather_update_flag)
        {
            OLED_ShowHzStringRow(16, 0, (const char *)"正在更新天气", 1);
        }
    }
    else
    {
        OLED_ShowHzStringRow(48, 48, (const char *)"退出", 1);
    }

    ssd1306_UpdateScreen();
}

/* 显示天气更新信息 */
static void Disp_ShowWeatherUpdate(void)
{
     //清空屏幕buffer
    ssd1306_Fill(Black);

    if (RT_FALSE == Bigiot_GetWeatherUpdateFlag())
    {
        thread_cycle = 1000;
        OLED_ShowHzStringRow(0, 24, (const char *)"天气代码设置有误", 1);
        Disp_SetLastDispFlag();
    }
    else
    {
        thread_cycle = 100;

        OLED_ShowHzStringRow(0, 12, (const char *)"天气代码设置成功", 1);
        OLED_ShowHzStringRow(32, 36, (const char *)"正在更新", 1);
    }

    ssd1306_UpdateScreen();
}

/* 显示时间 */
static void Disp_ShowTime(void)
{
    struct tm* cur_t;
    char disp_str[10];
    static const char *week_str[] = {"日", "一", "二", "三", "四", "五", "六"};
    struct netdev* net = netdev_get_by_name("esp0");
    static uint8_t wifi_conn_cnt = 0;
    static uint8_t iot_conn_cnt = 0;
    s_WeatherInfoType weather_info;
    static uint8_t date_time_cnt = 0;
    static uint8_t weather_cnt = 0;

    // 获取当前来自RTC的实时时钟信息
    cur_t = Rtc_GetDateTime();

    // 清空屏幕buffer
    ssd1306_Fill(Black);

    // 显示wifi logo
    if (netdev_is_internet_up(net) == 1)
    {
        wifi_conn_cnt = 0;
        OLED_DrawBmpImg(0, 0, wifi_logo_16bit, LOGO_SIZE(wifi_logo_16bit), 16, 1);
    }
    else
    {
        wifi_conn_cnt ^= 1;
        if (wifi_conn_cnt == 1)
        {
            OLED_DrawBmpImg(0, 0, wifi_logo_16bit, LOGO_SIZE(wifi_logo_16bit), 16, 1);
        }
    }

    // 显示IoT连接logo
    ssd1306_SetCursor(16, 4);
    if (1U == Bigiot_GetConnFlag())
    {
        ssd1306_WriteString("IoT", Font_7x10, White);
    }
    else
    {
        iot_conn_cnt ^= 1;
        if (iot_conn_cnt == 1)
        {
            ssd1306_WriteString("IoT", Font_7x10, White);
        }
    }

    // 显示天气
    weather_info = Weather_GetWeatherInfo();
    if (1U == weather_info.flag)
    {
        if (weather_cnt > 10)
        {
            weather_cnt = 0;
        }
        else if (weather_cnt > 5)
        {
            rt_sprintf(disp_str, "%02d%%|%02d", weather_info.humi, weather_info.temp);
            if (weather_info.temp < 0)
            {
                ssd1306_SetCursor(57, 0);
            }
            else
            {
                ssd1306_SetCursor(46, 0);
            }
            ssd1306_WriteString(disp_str, Font_11x18, White);
            OLED_ShowHz(112, 0, (const char *)"℃", 1 );
        }
        else
        {
            OLED_ShowHzStringRow(48, 0, (const char *)weather_info.weather_curr, 1);
        }
        weather_cnt ++;
    }
    else
    {
        ssd1306_SetCursor(64, 0);
        OLED_ShowHzStringRow(48, 0, (const char *)"天气获取中", 1);
    }

    // 显示时间信息
    ssd1306_SetCursor(18, 19);
    rt_sprintf(disp_str, "%02d:%02d", cur_t->tm_hour, cur_t->tm_min);
    ssd1306_WriteString(disp_str, Font_16x26, White);
    rt_sprintf(disp_str, "%02d", cur_t->tm_sec);
    ssd1306_SetCursor(100, 32);
    ssd1306_WriteString(disp_str, Font_7x10, White);

    // 显示日期信息
    if (date_time_cnt > 10)
    {
        date_time_cnt = 0;
    }
    else if (date_time_cnt > 5)
    {
        ssd1306_SetCursor(8, 46);
        rt_sprintf(disp_str, "%04d", cur_t->tm_year+1900);
        ssd1306_WriteString(disp_str, Font_11x18, White);
        OLED_ShowHz(52, 46, (const char *)"年", 1);
    }
    else
    {
        ssd1306_SetCursor(0, 46);
        rt_sprintf(disp_str, "%02d", cur_t->tm_mon+1);
        ssd1306_WriteString(disp_str, Font_11x18, White);
        OLED_ShowHz(22, 46, (const char *)"月", 1);
        ssd1306_SetCursor(38, 46);
        rt_sprintf(disp_str, "%02d", cur_t->tm_mday);
        ssd1306_WriteString(disp_str, Font_11x18, White);
        OLED_ShowHz(60, 46, (const char *)"日", 1);
    }
    date_time_cnt ++;

    OLED_ShowHzStringRow(80, 46, (const char *)"星期", 1);
    OLED_ShowHz(112, 46, (const char *)week_str[cur_t->tm_wday], 1);
    // 将OLED buffer中的数据打印在屏幕上
    ssd1306_UpdateScreen();

    thread_cycle = 100;
}

void Disp_MenuKeyPress(void)
{
    switch (disp_flg)
    {
        case DISP_TIME:
        {
            disp_flg = DISP_SETTING;
            break;
        }
        case DISP_WAVEFORM:
        {
            disp_flg = DISP_TIME;
            break;
        }
        case DISP_SETTING:
        {
            setting_flag ++;
            if (setting_flag > SETTING_EXIT)
            {
                setting_flag = SETTING_UPDATE_NTP;
            }
            if (setting_flag == SETTING_UPDATE_NTP)
            {
                ntp_update_flag = RT_FALSE;
            }
            if (setting_flag == SETTING_UPDATE_WEATHER)
            {
                weather_update_flag = RT_FALSE;
            }
            break;
        }
        default: break;
    }
}

void Disp_FuncKeyPress(void)
{
    switch (disp_flg)
    {
        case DISP_TIME:
        {
            disp_flg = DISP_WAVEFORM;
            break;
        }
        case DISP_WAVEFORM:
        {
            disp_flg = DISP_TIME;
            break;
        }
        case DISP_SETTING:
        {
            switch (setting_flag)
            {
                case SETTING_UPDATE_NTP:
                {
                    // 更新时间
                    if (!ntp_update_flag)
                    {
                        ntp_update_flag = RT_TRUE;
                        Esp8266_SetWorkingMode(ESP8266_NTP_SNYC);
                    }
                    break;
                }
                case SETTING_UPDATE_WEATHER:
                {
                    // 更新天气
                    if (!weather_update_flag)
                    {
                        weather_update_flag = RT_TRUE;
                        Esp8266_SetWorkingMode(ESP8266_WEATHER_SYNC);
                    }

                    break;
                }
                case SETTING_EXIT:
                {
                    disp_flg = DISP_TIME;
                    break;
                }
            }
            break;
        }
        default: break;
    }
}

void Disp_NtpUpdateSucc(void)
{
    ntp_update_flag = RT_FALSE;
}

void Disp_WeatherUpdateSucc(void)
{
    weather_update_flag = RT_FALSE;
}

//取绝对值函数
static int myabs(int a)
{
    return ((a < 0) ? (-a) : (a));
}

/* 显示心电图 */
static void Disp_ShowElectrocardiogram(void)
{
    uint16_t *disp_val;
    uint8_t x = 0;
    uint8_t y = 0;
    char bpm_str[10];

    disp_val = Ps_GetWaveformList();

    for (x = 0; x < 128; x++)
    {
        for (y = 0; y < 64; y++)
        {
            ssd1306_DrawPixel(x, y, Black);
        }
        if (x != 0)
        {
            if(myabs((uint16_t)disp_val[x]-(uint16_t)disp_val[x-1]) > 1)
            {
                if(disp_val[x] > disp_val[x-1])
                {
                    for(y = disp_val[x-1]; y < disp_val[x]; y++)
                    {
                        ssd1306_DrawPixel(x, y, 1);      //在相应的像素点上打印
                    }
                }
                else
                {
                    for(y = disp_val[x]; y < disp_val[x-1]; y++)
                    {
                        ssd1306_DrawPixel(x, y, 1);      //在相应的像素点上打印
                    }
                }
            }
        }

        ssd1306_DrawPixel(x, disp_val[x], White);
    }

    /* 显示心率值 */
//    if (Ps_GetQsFlg() == true)
//    {
        Ps_ClrQsFlg();
        ssd1306_SetCursor(84, 0);
        rt_sprintf(bpm_str, "%3d/min", Ps_GetBpm());
        ssd1306_WriteString(bpm_str, Font_6x8, White);
//    }
    ssd1306_UpdateScreen();
    thread_cycle = 20;
}


//在指定位置显示一个汉字
//x:0~127
//y:0~63
//hz_c:输入汉字，汉字需要先建模
//color:0,反白显示;1,正常显示
static void OLED_ShowHz(uint8_t x, uint8_t y, const char hz_c[], SSD1306_COLOR color)
{
    uint8_t temp, t, t1;
    uint8_t y0 = y;
    uint8_t csize = 32u;
    uint8_t chr = 0;
    uint8_t flag = 0;

    for (t=0; t<(sizeof(hz_char)/sizeof(hz_char[0])); t++)
    {
        if(rt_strcmp(hz_char[t], hz_c) == 0)
        {
            chr = t;
            flag = 1;    //找到了建模的汉字
            break;
        }
    }

    if(1 == flag)
    {
        chr <<= 1u;

        for(t=0; t<csize; t++)
        {
            if(16U == t)
                chr += 1;

            temp=(White == color) ? (hz_code[chr][t%16]):(~hz_code[chr][t%16]);

            for(t1=0; t1<8; t1++)
            {
                if(temp & 0x80)
                    ssd1306_DrawPixel(x, y, White);
                else
                    ssd1306_DrawPixel(x, y, Black);

                temp <<= 1;
                y++;
                if(16U == (y-y0))
                {
                    y = y0;
                    x++;
                    break;
                }
            }
        }
    }
}

//显示连续的汉字,一行显示，一行128像素，最多显示8个
//hz_len: 要显示的函数的长度
//汉字大小为16像素，其他像素的汉字暂时不支持
//一个汉字的长度为三个字节，并且包含一个结束符
static void OLED_ShowHzStringRow(uint8_t x, uint8_t y, const char *hz_s, SSD1306_COLOR color)
{
    uint8_t i;
    char chr[4];
    uint8_t len;

    len = rt_strlen(hz_s);    //计算汉字字符串的长度
    for(i=0; i<(len-1); i+=3)
    {
        rt_sprintf(chr, "%c%c%c", hz_s[i], hz_s[i+1], hz_s[i+2]);
        OLED_ShowHz(x+((i/3)<<4), y, chr, color);
    }
}

// 显示图片
static void OLED_DrawBmpImg(uint8_t x,
                             uint8_t y,
                             const uint8_t bmp[][8],
                             uint32_t len,
                             uint8_t size,
                             SSD1306_COLOR color)
{
    uint16_t t, t1;
    uint8_t  y_end;
    uint8_t  temp;
    uint16_t len2 = 0u;

    y_end = y;

    len2 = (uint16_t)((len) / ((uint8_t)(size/8)));

    for(t=0; t<len; t++)
    {
        temp=(White == color) ?
             (bmp[(uint8_t)(t/8)][(uint8_t)(t%8)]):(~bmp[(uint8_t)(t/8)][(uint8_t)(t%8)]);

        for(t1=0; t1<8; t1++)
        {
            if(temp&0x80)
                ssd1306_DrawPixel(x, y, White);
            else
                ssd1306_DrawPixel(x, y, Black);

            temp <<= 1u;
            y++;
            if((y-y_end) == len2)
            {
                y = y_end;
                x ++;
                break;
            }
        }
    }
}

e_DispFlag Disp_GetDispFlag(void)
{
    return disp_flg;
}

void Disp_SetDispFlag(e_DispFlag flag)
{
    // 保留却换之前的显示界面
    if (DISP_UPDATE_WEATHER != disp_flg)
        disp_flg_last = disp_flg;
    disp_flg = flag;
}

void Disp_SetLastDispFlag(void)
{
    disp_flg = disp_flg_last;
}
